package com.wingsboat.common.protect.keyresolver.impl;

import cn.hutool.core.util.ArrayUtil;
import com.wingsboat.common.core.utils.JoinPointUtil;
import com.wingsboat.common.protect.annotation.Idempotent;
import com.wingsboat.common.protect.aspect.IdempotentAspect;
import com.wingsboat.common.protect.keyresolver.IdempotentKeyResolver;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 基于 Spring EL 表达式，
 *
 * @author wangzhong
 */
@Component
public class ExpressionIdempotentKeyResolver implements IdempotentKeyResolver, InitializingBean {

    @Autowired
    private IdempotentAspect idempotentAspect;

    private final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
    private final ExpressionParser expressionParser = new SpelExpressionParser();

    @Override
    public String resolver(ProceedingJoinPoint joinPoint, Idempotent idempotent) {
        // 获得被拦截方法参数名列表
        Method method = JoinPointUtil.getMethod(joinPoint);
        Object[] args = joinPoint.getArgs();
        String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method);
        // 准备 Spring EL 表达式解析的上下文
        StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
        if (ArrayUtil.isNotEmpty(parameterNames)) {
            for (int i = 0; i < parameterNames.length; i++) {
                evaluationContext.setVariable(parameterNames[i], args[i]);
            }
        }

        // 解析参数
        Expression expression = expressionParser.parseExpression(idempotent.spEl());
        String value = expression.getValue(evaluationContext, String.class);
        return value;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        idempotentAspect.addIdempotentKeyResolver(this);
    }

}
